package com.neveu.android.ds.socketmessenger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class NetServent {

	Socket clientSock;
	ServerSocket serverSock;
	private String loopbackIP;
	private boolean connected;
	private int listenPort;
	private int connectPort;
	private PrintWriter pw;
	private MessageListener msgListener;
	
	
	public NetServent(String loopbackIP, String emulatorIP, int listenPort, int clientPort)
	{
		connected = false;
		this.loopbackIP = loopbackIP;
		this.listenPort = listenPort;
		this.connectPort = clientPort;
		
		try {
			serverSock = new ServerSocket(listenPort);
		}catch(IOException e){
			System.err.println("Could not establish listening socket on port " + listenPort);
		}

		new Thread(new Runnable() {
			public void run()
			{
				try {
					clientSock = serverSock.accept();
					connected = true;
				}catch(IOException e) {
					/* this is caught whether there is a legitimate socket issue, or if serverSock
					 * has been explicitly closed. Either way, readInput() is not reached, which is what we want.
					 */
//					System.err.println("Could not establish listening socket on port ");
				}
				
				readInput();
			}}).start();
	}
	
	public boolean connect()
	{
		if(connected)
		{
			return true;
		}

		try{
			clientSock = new Socket(loopbackIP, connectPort);
			
		} catch (UnknownHostException e) {
            System.err.println("Don't know about host: " + loopbackIP + ".");
            return false;
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for "
                               + "the connection to: " + loopbackIP + ".");
            return false;
        }
		
		connected = true;
		
		/* Close listening socket, as it will never be used. */
		try {
			if(serverSock.isBound())
				serverSock.close();
		} catch (IOException e1) {
//			e1.printStackTrace();
		}
		
		
		/* Start read thread, if instance is client. */
		new Thread(new Runnable() {
			public void run()
			{
				readInput();
			}
		}).start();
		
		return true;
	}
	
	public void sendMessage(String msg)
	{
		if(pw == null && connected)
		{
			try{
				pw = new PrintWriter(clientSock.getOutputStream(), true);
	        } catch (IOException e) {
	        	System.err.println("Could not get socket output stream");
	        }
		}
		
		pw.println(msg);
	}
	
	public synchronized void readInput()
	{
		String inStr = "";
		BufferedReader in;
		
		try{
			in = new BufferedReader(
				    new InputStreamReader(
				    		clientSock.getInputStream()));

//			while(clientSock.isBound())

			/* How to nicely interrupt this blocking call when we wish to exit?? */
				while((inStr = in.readLine()) != null)
				{
					
					if(msgListener != null)
						msgListener.receiveMessage(inStr + "\n");
					else
						System.out.println(inStr);
				}

				in.close();
				clientSock.close();
				
		}catch (IOException e) {
//			System.err.println(e.getMessage());
		}
		finally{
			pw.close();
		}
	}
		
	
	
	public void disconnect()
	{
		try{
			
			clientSock.close();
			serverSock.close();
		}catch(IOException e)
		{
			System.err.println(e.getMessage());
		}
	}
	
	public void setMessageListener(MessageListener ml)
	{
		msgListener = ml;
	}
}
